package com.puff.jdbc.tx.proxy;

import java.lang.reflect.Method;
import java.sql.Connection;

import com.puff.exception.ExceptionUtil;
import com.puff.framework.annotation.Transaction;
import com.puff.jdbc.core.DataBase;
import com.puff.jdbc.core.DbManager;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 事务拦截器
 * 
 * @author dongchao
 * @since 0.1
 */
public class CglibProxy implements TXProxy, MethodInterceptor {

	private Class<?> clazz;

	@Override
	public Object getProxy() {
		return Enhancer.create(clazz, this);
	}

	public CglibProxy(Class<?> clazz) {
		this.clazz = clazz;
	}

	public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		Object result = null;
		method.setAccessible(true);
		Transaction tran = method.getAnnotation(Transaction.class);
		if (tran != null) {
			Connection conn = DataBase.getThreadLocalConnection();
			// 嵌套事务
			if (conn != null) {
				return proxy.invokeSuper(target, args);
			} else {
				Boolean autoCommit = null;
				try {
					conn = DbManager.getConnection(tran.value());
					autoCommit = conn.getAutoCommit();
					DataBase.setThreadLocalConnection(conn);
					conn.setAutoCommit(false);
					result = proxy.invokeSuper(target, args);
					conn.commit();
				} catch (Throwable t) {
					if (conn != null)
						try {
							conn.rollback();
						} catch (Exception e) {
						}
					ExceptionUtil.throwRuntime(t);
				} finally {
					try {
						if (conn != null) {
							if (autoCommit != null)
								conn.setAutoCommit(autoCommit);
							conn.close();
						}
					} catch (Throwable t) {
					} finally {
						com.puff.jdbc.core.DataBase.removeThreadLocalConnection();
					}
				}
			}
		} else {
			result = proxy.invokeSuper(target, args);
		}
		return result;
	}

}
